package com.example.event_resource_java.authority.server.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.event_resource_java.authority.dao.UserDao;
import com.example.event_resource_java.authority.mapper.ClassMapper;
import com.example.event_resource_java.authority.server.UserServer;
import com.example.event_resource_java.commons.domain.UserDO;
import com.example.event_resource_java.commons.enums.ApiEnumError;
import com.example.event_resource_java.commons.enums.Constants;
import com.example.event_resource_java.commons.enums.EnumErrorCode;
import com.example.event_resource_java.commons.exce.JinZhiException;
import com.example.event_resource_java.commons.model.LoginBody;
import com.example.event_resource_java.commons.util.JWTUtil;
import com.example.event_resource_java.commons.util.PasswdUtils;
import com.example.event_resource_java.commons.vo.LoginVO.TokenVO;
import com.example.event_resource_java.starinside.config.CacheConfiguration;
import com.example.event_resource_java.starinside.config.JWTConfigProperties;
import com.example.event_resource_java.starinside.config.JwtConfigTime;
import com.example.event_resource_java.starinside.exception.IFastApiException;
import com.example.event_resource_java.starinside.redis.RedisTime;
import com.example.event_resource_java.starinside.redis.RedisUtil;
import com.example.event_resource_java.starinside.spring.SpringContextHolder;
import com.example.event_resource_java.test.dao.TestDao;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.stereotype.Service;

import java.util.Base64;
import java.util.List;
import java.util.Objects;


/**
 * packageName com.example.event_resource_java.authority.server.impl
 *
 * @author xzy
 * @version JDK 8
 * @className UserServerImpl
 * @date 2024/4/1
 * @description
 */

@Service
public class UserServerImpl extends ServiceImpl<TestDao, UserDO> implements UserServer {

    @Autowired
    private ClassMapper classMapper;
    @Autowired
    private UserDao userDao;

    /**
     * @auther: ak
     * @Description 图形验证码校验
     * @param:
     * @return:
     * @date: 2024/4/3 16:38
     */
    @Override
    public String verifyCode(String username, String code, String uuid) {

        // 验证码校验
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        if (Objects.isNull(RedisUtil.get(verifyKey))) {
            return "验证码校验失败,请联系管理员！";
        }
        Object captcha = RedisUtil.get(verifyKey);

        // 数据一致性
        RedisUtil.del(verifyKey);

        if (captcha == null) {
            //验证码不存在
            return EnumErrorCode.userLoginFai1l.getMsg();
        }

        if (!code.equals(captcha)) {
            // 验证码错误
            return EnumErrorCode.userLoginFai1l1.getMsg();
        }

        return EnumErrorCode.success.getMsg();
    }

    @Override
    public String judge(LoginBody loginBody) {
        QueryWrapper<UserDO> userDOQueryWrapper = new QueryWrapper<>();
        userDOQueryWrapper.eq("username", loginBody.getUsername().trim());
        userDOQueryWrapper.eq("user_from", 1);
        UserDO userDO = this.getOne(userDOQueryWrapper);

        //Integer existClass = classMapper.isExistsStudent(userDO.getId());
        if (ObjectUtil.isNull(userDO)) {
            if (loginBody.getType().equals(1)) {
                return "账号不存在 请联系管理员";
            } else if (loginBody.getType().equals(0)) {
                return "账号不存在 请联系老师";
            }
        }

        if (!userDO.getType().equals(loginBody.getType())) {
            return "账号不存在 请联系管理员";
        }
        return "请求成功";
    }

    /**
     * @auther: ak
     * @Description 忘记密码找回
     * @param:
     * @return:
     * @date: 2024/4/7 14:49
     */
    @Override
    public String forgetPassword(LoginBody loginBody) {
        String smsKey = Constants.SMS_CODE_KEY + loginBody.getMobile();
        String smsLimitKey = Constants.SMS_LIMIT_KEY + loginBody.getMobile();

        QueryWrapper<UserDO> userDOQueryWrapper = new QueryWrapper<>();
        userDOQueryWrapper.eq("mobile", loginBody.getMobile());
        UserDO userDO = this.getOne(userDOQueryWrapper);

        if (ObjectUtil.isNull(userDO)) {
            return "用户不存在!";
        }

        // 单个用户单天最多可获取 5 次 24h = 86400s
        if (ObjectUtil.isEmpty(RedisUtil.get(smsKey))) {
            RedisUtil.set(smsLimitKey, 1, 86400);
            return "验证码已过期";
        } else if ((Integer) RedisUtil.get(smsLimitKey) == 5) {
            return "获取次数已达上限 请明天重试";
        } else {
            RedisUtil.set(smsLimitKey, (Integer) RedisUtil.get(smsLimitKey) + 1, 86400);
        }

        // 获取短信验证码
        String code = (String) RedisUtil.get(smsKey);

        // 验证码错误
        if (!loginBody.getCode().equals(code)) {
            return "请输入正确的验证码";
        }

        // 存储新密码
        String password = new String(Base64.getDecoder().decode(loginBody.getPassword()));
        String newPassword = PasswdUtils.get(password, userDO.getSalt());
        userDO.setPassword(newPassword);

        boolean isSuccess = this.updateById(userDO);

        //RedisUtil.del(smsLimitKey);
        return isSuccess == true ? "修改成功" : "修改失败";
    }


    /**
     * Holder for lazy-init
     */
    private static class Holder {
        static final JWTConfigProperties jwtConfig = SpringContextHolder.getBean(JWTConfigProperties.class);
        static final Cache logoutTokens = CacheConfiguration.dynaConfigCache(jwtConfig.getExpireTokenKeyPrefix(), jwtConfig
                .getRefreshTokenExpire());
    }

    @Override
    public void verifyToken(String token, boolean isRefreshToken) {
        ensureAvailable(token, isRefreshToken);
    }

    private void ensureAvailable(String token, boolean isRefreshToken) {
        if (StringUtils.isBlank(token)) {
            throw new IFastApiException(ApiEnumError.apiAuthorizationInvalid.getCodeStr());
        }
        String wxUserId = JWTUtil.getWxUserId(token);
        if (StringUtils.isBlank(wxUserId)) {
            throw new IFastApiException(ApiEnumError.apiAuthorizationInvalid.getCodeStr());
        }
        if (Holder.logoutTokens.get(token) != null) {
            throw new IFastApiException(ApiEnumError.apiAuthorizationLoggedout.getCodeStr());
        }
//
        UserDO userDO = baseMapper.selectById(wxUserId);

        if (userDO == null) {
            throw new IFastApiException(ApiEnumError.apiAuthorizationInvalid.getCodeStr());
        }

        JWTUtil.verify(token, userDO.getId() + "", userDO.getId() + userDO.getUsername(), isRefreshToken);

    }

    @Override
    public String getToken1(String mobile) {
        QueryWrapper<UserDO> wrapper = new QueryWrapper();
        wrapper.like("mobile", mobile);
        wrapper.eq("user_from", 1);
        List<UserDO> userDO = userDao.selectList(wrapper);
        if (userDO.size() == 0) {
            throw new JinZhiException(ApiEnumError.apiAuthorizationWxLoginFailed.getCode(), ApiEnumError.apiAuthorizationWxLoginFailed.getMsg());
        }
        //将用户信息储存到redis里面
//         redisUtil.set(token,userDO.getId(), RedisTime.redisTimeDay);

        return createToken(userDO.get(0), 1);
    }

    private String createToken(UserDO userDO,Integer type) {
        TokenVO vo = new TokenVO();
        String token = JWTUtil.jzSign(userDO, JwtConfigTime.JwtVerify2, JwtConfigTime.time6.longValue());
        //String refreshToken = JWTUtil.sign(userDO.getId() + "", userDO.getId() + userDO.getMobile(), 2l, true);
        vo.setToken(token);
        vo.setRefleshToken(token);
        vo.setTokenExpire(2l);
        vo.setRefreshTokenExpire(7l);
        return vo.getToken();
    }
}